﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NDF.Collections.Generic
{
    /// <summary>
    /// 为 <see cref="System.Collections.IEqualityComparer"/> 泛型接口提供通用实现。
    /// 定义方法以支持对象的相等比较。
    /// </summary>
    /// <typeparam name="T">要比较的对象的类型。</typeparam>
    public class GenericEqualityComparer<T> : EqualityComparer<T>
    {
        private Func<T, T, bool> comparer;
        private Func<T, int> hashCodeGetter;

        public GenericEqualityComparer()
        {
            this.comparer = DefaultComparer;
            this.hashCodeGetter = DefaultHashCodeGetter;
        }

        public GenericEqualityComparer(Func<T, T, bool> comparer)
        {
            this.Comparer = comparer;
        }

        public GenericEqualityComparer(Func<T, int> hashCodeGetter)
        {
            this.HashCodeGetter = hashCodeGetter;
        }

        public GenericEqualityComparer(Func<T, T, bool> comparer, Func<T, int> hashCodeGetter)
            : this(comparer)
        {
            this.HashCodeGetter = hashCodeGetter;
        }


        public override bool Equals(T x, T y)
        {
            return this.Comparer(x, y);
        }

        public override int GetHashCode(T obj)
        {
            return this.HashCodeGetter(obj);
        }


        public Func<T, T, bool> Comparer
        {
            get
            {
                return this.comparer == null ? DefaultComparer : this.comparer;
            }
            set { this.comparer = value; }
        }

        public Func<T, int> HashCodeGetter
        {
            get
            {
                return this.hashCodeGetter == null ? DefaultHashCodeGetter : this.hashCodeGetter;
            }
            set { this.hashCodeGetter = value; }
        }



        private static GenericEqualityComparer<T> _default;

        public static new GenericEqualityComparer<T> Default
        {
            get
            {
                if (_default == null)
                {
                    _default = new GenericEqualityComparer<T>();
                }
                return _default;
            }
        }



        public static IEqualityComparer<T> Create(Func<T, T, bool> comparer)
        {
            return new GenericEqualityComparer<T>(comparer);
        }

        public static IEqualityComparer<T> Create(Func<T, int> hashCodeGetter)
        {
            return new GenericEqualityComparer<T>(hashCodeGetter);
        }

        public static IEqualityComparer<T> Create(Func<T, T, bool> comparer, Func<T, int> hashCodeGetter)
        {
            return new GenericEqualityComparer<T>(comparer, hashCodeGetter);
        }



        public static Func<T, T, bool> DefaultComparer = (a, b) => EqualityComparer<T>.Default.Equals(a, b);

        public static Func<T, int> DefaultHashCodeGetter = a => EqualityComparer<T>.Default.GetHashCode(a);
    }
}
